package Java基础.JUC同步工具.AQS;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @Description 自定义锁支持公平非公平
 */
public class CustomReentrantLock implements Lock {

    private final Sync sync;

    // 通过构造器选择公平/非公平模式
    public CustomReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    // 内部同步器基类
    private abstract static class Sync extends AbstractQueuedSynchronizer {
        // 尝试获取锁（由子类实现）
        protected abstract boolean tryAcquire(int acquires);

        // 尝试释放锁
        @Override
        protected boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread()) {
                throw new IllegalMonitorStateException();
            }
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        // 判断是否持有锁
        @Override
        protected boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        // 创建条件变量
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // 添加一个公共方法，暴露 state
        public int getLockState() {
            return getState(); // 在子类内部调用 protected 方法
        }

        // 添加一个公共方法，暴露当前持有锁的线程
        public Thread getOwnerThread() {
            return getExclusiveOwnerThread(); // 在子类内部调用 protected 方法
        }


    }

    // 非公平锁实现
    private static class NonfairSync extends Sync {
        @Override
        protected boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // 直接尝试 CAS 获取，不检查队列
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            } else if (current == getExclusiveOwnerThread()) {
                // 可重入逻辑
                int nextc = c + acquires;
                if (nextc < 0) throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

    // 公平锁实现
    private static class FairSync extends Sync {
        @Override
        protected boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // 公平锁核心：先检查是否有前驱节点
                if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            } else if (current == getExclusiveOwnerThread()) {
                // 可重入逻辑
                int nextc = c + acquires;
                if (nextc < 0) throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

    //------------------- Lock 接口方法实现 -------------------
    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    // 其他工具方法
    public boolean isLocked() {
        return sync.getLockState() != 0;
    }

    public boolean isFair() {
        return sync instanceof FairSync;
    }

    public Thread getOwner() {
        return sync.getOwnerThread();
    }
}